#ifndef _SERIALIZATION_H_
#define _SERIALIZATION_H_
#include <string>
#include <yaml-cpp/yaml.h>
#include <Core/Reflect.h>
#include <GameObject/Object.h>
#include <GameObject/Scene.h>

namespace Engine2D
{
    class Serialization
    {
    public:
        template<typename T>
        static YAML::Node Serialize(T & src);
        template<typename T>
        static T DeSerialize(YAML::Node & node);
        static YAML::Node SerializeObject(std::shared_ptr<IObject> obj);
        static std::shared_ptr<IObject> DeSerializeObject(YAML::Node & node);
        static YAML::Node SerializeScene(std::shared_ptr<Scene> scene);
        static std::shared_ptr<Scene> DeSerializeScene(YAML::Node & node);
    };
    
    template <typename T>
    inline YAML::Node Serialization::Serialize(T &src)
    {
        Reflect<std::decay_t<T>> info;
        YAML::Node root;
        info.Foreach([&](auto field) {
            if constexpr (field.Reflectable()) {
                root[field.name] = Serialize(field.Value(src));
            } else {
                root[field.name] = field.Value(src);
            }
        });
        return root;
    }

    template <typename T>
    inline T Serialization::DeSerialize(YAML::Node &node)
    {
        auto obj = T();
        Reflect<std::decay_t<T>> info;
        info.Foreach([&](auto field) {
            if constexpr (field.Reflectable()) {
                field.Value(obj, DeSerialize<decltype(field)::Type>(node[field.name]));
            } else {
                field.Value(obj, node[field.name].as<decltype(field)::Type>());
            }
        });
        return obj;
    }
} // namespace Engine2D

#endif